package com.qiyue.admin.rpc.service;

import com.qiyue.admin.auth.utils.jwt.utils.JWTAuthUtils;
import com.qiyue.admin.auth.utils.jwt.utils.UserAuthUtil;
import com.qiyue.admin.biz.base.ElementBiz;
import com.qiyue.admin.biz.base.MenuBiz;
import com.qiyue.admin.biz.base.ResourceAuthorityBiz;
import com.qiyue.admin.biz.base.UserBiz;
import com.qiyue.admin.constant.AdminCommonConstant;
import com.qiyue.admin.entity.base.Element;
import com.qiyue.admin.entity.base.Menu;
import com.qiyue.admin.entity.base.ResourceAuthority;
import com.qiyue.admin.entity.base.User;
import com.qiyue.admin.vo.FrontUser;
import com.qiyue.admin.vo.MenuTree;
import com.qiyue.api.vo.authortiy.PermissionInfo;
import com.qiyue.api.vo.user.UserInfo;
import com.qiyue.common.constant.CommonConstants;
import com.qiyue.common.utils.TreeUtil;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * Created by y747718944 on 2018/2/7
 *  权限许可
 */
@Service
public class PermissionService {

    @Autowired
    private UserBiz userBiz;
    @Autowired
    private MenuBiz menuBiz;
    @Autowired
    private ElementBiz elementBiz;
//    @Autowired
//    private UserAuthUtil userAuthUtil;//  分布式jwt解码工具
    @Autowired
    private ResourceAuthorityBiz resourceAuthorityBiz;

    @Autowired
    private JWTAuthUtils jwtAuthUtils;//jwt解码工具

    private BCryptPasswordEncoder encoder = new BCryptPasswordEncoder(12);

    /**
     * 登录验证 分布式启用
     * @param accout
     * @param paw
     * @return
     */
    public UserInfo validate(String accout,String paw){
        UserInfo info = new UserInfo();
        User user = userBiz.getUserByAccout(accout);
        if (encoder.matches(paw, user.getPassword())) {
            BeanUtils.copyProperties(user, info);
            info.setId(user.getId().toString());
        }
         return info;
    }


    /**
     * 通过 token信息获取 userInfo
     *  @param token
     * @return FrontUser 视图模型
     * @throws Exception
     */
    public FrontUser getUserInfo(String token) throws Exception {
       String account = jwtAuthUtils.getInfoFromToken(token).getAccount();
        if (account == null) {
            return null;
        }
        UserInfo user =  this.getUserByAccount(account);
        FrontUser frontUser = new FrontUser();
        BeanUtils.copyProperties(user, frontUser);
        List<PermissionInfo> permissionInfos = this.getPermissionByAccount(account);

        //进行类型过滤
        Stream<PermissionInfo> menus = permissionInfos.parallelStream().filter((permission) -> {
            return permission.getType().equals(CommonConstants.ResourceConstant.RESOURCE_TYPE_MENU);
        });
        frontUser.setMenus(menus.collect(Collectors.toList()));
        Stream<PermissionInfo> elements = permissionInfos.parallelStream().filter((permission) -> {
            return !permission.getType().equals(CommonConstants.ResourceConstant.RESOURCE_TYPE_MENU);
        });
        frontUser.setElements(elements.collect(Collectors.toList()));
        return frontUser;
    }

    /**
     * 通过 token获取 菜单
     * @param token
     * @return
     * @throws Exception
     */
    public List<MenuTree> getMenusByAccount(String token) throws Exception {
        String account = jwtAuthUtils.getInfoFromToken(token).getAccount();
        if (account == null) {
            return null;
        }
        User user = userBiz.getUserByAccout(account);
      List<MenuTree> trees = menuBiz.getUserAuthorityMenuByUserId(user.getId())
                .stream()
                .map(menu -> {
                    MenuTree   node = new MenuTree();
                    BeanUtils.copyProperties(menu, node);
                    return  node;
                })
                .collect(Collectors.toList());

        return   TreeUtil.bulid(trees, AdminCommonConstant.ROOT);
    }




    /**
     * 通过账号获取用户信息
     * @param account
     * @return
     */
    public UserInfo getUserByAccount(String account) {
        UserInfo info = new UserInfo();
        User user = userBiz.getUserByAccout(account);
        BeanUtils.copyProperties(user, info);
        info.setId(user.getId().toString());
        return info;
    }


    /**
     * 通过账号获取用户的资源许可
     * @param account
     * @return
     */
    public List<PermissionInfo> getPermissionByAccount(String account) {
        User user = userBiz.getUserByAccout(account);
        List<Menu> menus = menuBiz.getUserAuthorityMenuByUserId(user.getId());
        List<PermissionInfo> result = new ArrayList<PermissionInfo>();
        getPermissionMenuToVO(menus, result);
        List<Element> elements = elementBiz.getAuthorityElementByUserId(user.getId() + "");
        getPermissionElementToVO(elements,result);
        return result;
    }

    /**
     *  获得菜单权限 视图模型
     * @param menus
     * @param resultVO
     */
    private void getPermissionMenuToVO(List<Menu> menus, List<PermissionInfo> resultVO) {
        PermissionInfo info;
        for (Menu menu : menus) {
            if (StringUtils.isBlank(menu.getHref())) {
                menu.setHref("/" + menu.getCode());
            }
            info = new PermissionInfo();
            info.setCode(menu.getCode());
            info.setType(AdminCommonConstant.RESOURCE_TYPE_MENU);
            info.setName(AdminCommonConstant.RESOURCE_ACTION_VISIT);
            String uri = menu.getHref();
            if (!uri.startsWith("/")) {
                uri = "/" + uri;
            }
            info.setUri(uri);
            info.setMethod(AdminCommonConstant.RESOURCE_REQUEST_METHOD_GET);
            resultVO.add(info
            );
            info.setMenu(menu.getTitle());
        }
    }

    /**
     *  获得组件权限 视图模型
     * @param elements
     * @param resultVO
     */
    private void getPermissionElementToVO( List<Element> elements,List<PermissionInfo> resultVO) {
        PermissionInfo info;
        for (Element element : elements) {
            info = new PermissionInfo();
            info.setCode(element.getCode());
            info.setType(element.getType());
            info.setUri(element.getUri());
            info.setMethod(element.getMethod());
            info.setName(element.getName());
            info.setMenu(element.getTitle());
            resultVO.add(info);
        }
    }

}
